import * as lodash from 'lodash';
import { ColorValue, FlexAlignType, StyleProp, ViewStyle } from 'react-native';
import {
  TBasicAnimatedValue,
  TContainerProps,
  TContainerPropsBase,
  TStringNumber,
} from './Types';

export function convert(input: any, mustNumber?: boolean): number | undefined {
  if (typeof input === 'number' && isNaN(input)) return undefined;
  const converted = +input!;
  const dft: number = mustNumber ? undefined : input;
  return isNaN(converted) ? dft : converted;
}

export function isAnimated(
  attr: TBasicAnimatedValue<number | string>
): boolean {
  return !!attr && isNaN(+attr!);
}

export function getWidthHeight(props: TContainerProps) {
  const keys = Object.keys(props);
  if (props.wh) {
    if (keys.indexOf('wh') > keys.indexOf('w')) props.w = props.wh;
    if (keys.indexOf('wh') > keys.indexOf('h')) props.h = props.wh;
  }
  if (props.whr) {
    if (keys.indexOf('whr') > keys.indexOf('w')) props.w = props.whr;
    if (keys.indexOf('whr') > keys.indexOf('h')) props.h = props.whr;
    props.br = convert(props.whr)! / 2;
  }
}

export function bs(props: TContainerPropsBase) {
  getWidthHeight(props);
  getMargin(props);
  getPadding(props);
  getBorder(props);
  const style: StyleProp<ViewStyle> = {
    flex: props.f === true ? 1 : convert(props.f),
    flexGrow: props.fg === true ? 1 : convert(props.fg),
    flexDirection: props.row ? 'row' : undefined,
    justifyContent: jcMap[props.jc!],
    alignItems: aiMap[props.ai!],
    alignSelf: aiMap[props.as!],
    flexWrap: props.wrap || props.fwp ? 'wrap' : undefined,
    overflow: props.of ? 'hidden' : undefined,
    width: convert(props.w),
    height: convert(props.h),
    maxWidth: convert(props.maxW),
    minWidth: convert(props.minW),
    maxHeight: convert(props.maxH),
    minHeight: convert(props.minH),
    margin: convert(props.m as TStringNumber),
    marginHorizontal: convert(props.mh),
    marginVertical: convert(props.mv),
    marginTop: convert(props.mt),
    marginBottom: convert(props.mb),
    marginLeft: convert(props.ml),
    marginRight: convert(props.mr),
    padding: convert(props.p as TStringNumber),
    paddingHorizontal: convert(props.ph),
    paddingVertical: convert(props.pv),
    paddingTop: convert(props.pt),
    paddingBottom: convert(props.pb),
    paddingLeft: convert(props.pl),
    paddingRight: convert(props.pr),
    borderTopWidth: convert(props.bwt) as number,
    borderBottomWidth: convert(props.bwb) as number,
    borderLeftWidth: convert(props.bwl) as number,
    borderRightWidth: convert(props.bwr) as number,
    borderWidth: convert(props.bw as TStringNumber, true) as number,
    borderTopColor: props.bct,
    borderBottomColor: props.bcb,
    borderLeftColor: props.bcl,
    borderRightColor: props.bcr,
    borderColor: props.bc as ColorValue,
    borderTopLeftRadius: convert(props.brtl) as number,
    borderTopRightRadius: convert(props.brtr) as number,
    borderBottomRightRadius: convert(props.brbr) as number,
    borderBottomLeftRadius: convert(props.brbl) as number,
    borderRadius: convert(props.br as TStringNumber, true) as number,
    backgroundColor: props.bg,
    zIndex: props.z ? +props.z : undefined,
    position: props.pos !== undefined ? 'absolute' : 'relative',
    opacity: convert(props.op as number) as number,
    transform: [],
  };
  if (props.sd) {
    const sd: StyleProp<ViewStyle> = {
      elevation: 10,
      shadowColor: '#000',
      shadowOffset: {
        width: 0,
        height: props.sd === 'top' ? -2 : 2,
      },
      shadowOpacity: 0.15,
      shadowRadius: 5,
    };
    Object.assign(style, sd);
  }

  Object.assign(style, getTransform(props), getPos(props));
  return lodash.pickBy(style, v => v !== undefined);
}

function getTransform(props: TContainerProps) {
  const style: StyleProp<ViewStyle> = { transform: [] };
  const transforms: any[] = [];

  if (props.tx) {
    transforms.push({ translateX: convert(props.tx) as number });
    delete props.tx;
  }
  if (props.ty) {
    transforms.push({ translateY: convert(props.ty) as number });
    delete props.ty;
  }
  if (props.scale) {
    transforms.push({ scale: convert(props.scale) as number });
    delete props.scale;
  }
  if (props.sx) {
    transforms.push({ scaleX: convert(props.sx) as number });
    delete props.sx;
  }
  if (props.sy) {
    transforms.push({ scaleY: convert(props.sy) as number });
    delete props.sy;
  }
  if (props.rt) {
    transforms.push({ rotate: convert(props.rt) as any });
    delete props.rt;
  }
  if (props.sb) {
    style.justifyContent = 'space-between';
    delete props.sb;
  }
  if (props.sa) {
    style.justifyContent = 'space-around';
    delete props.sa;
  }

  if (transforms.length > 0) {
    style.transform = transforms;
  }

  return style;
}

export function getPos(props: TContainerProps) {
  const style: StyleProp<ViewStyle> = {};
  if (props.pos !== undefined) {
    if (!Array.isArray(props.pos)) {
      props.pos = [props.pos, props.pos, props.pos, props.pos];
    }
    style.top = convert(props.pos[0]);
    style.left = convert(props.pos[1]);
    style.bottom = convert(props.pos[2]);
    style.right = convert(props.pos[3]);
  }

  return style;
}

export function getMargin(props: TContainerProps) {
  if (!Array.isArray(props.m)) {
    return;
  }
  const len = props.m.length;
  const keys = Object.keys(props);
  const mIdx = keys.indexOf('m');
  const m = props.m;

  if (len === 1) {
    props.m = props.m[0];
    return;
  }
  if (len === 2) {
    if (keys.indexOf('mh') < mIdx) props.mh = props.m[0];
    if (keys.indexOf('mv') < mIdx) props.mv = props.m[1];
  } else if (len === 3) {
    if (keys.indexOf('mt') < mIdx) props.mt = m[0];
    if (keys.indexOf('mh') < mIdx) props.mh = m[1];
    if (keys.indexOf('mb') < mIdx) props.mb = m[2];
  } else if (len === 4) {
    if (keys.indexOf('mt') < mIdx) props.mt = m[0];
    if (keys.indexOf('mr') < mIdx) props.mr = m[1];
    if (keys.indexOf('mb') < mIdx) props.mb = m[2];
    if (keys.indexOf('ml') < mIdx) props.ml = m[3];
  }
  delete props.m;
}

export function getPadding(props: TContainerProps) {
  if (!Array.isArray(props.p)) {
    return;
  }
  const len = props.p.length;
  const keys = Object.keys(props);
  const pIdx = keys.indexOf('p');
  const p = props.p;
  if (len === 1) {
    props.p = props.p[0];
    return;
  }
  if (len === 2) {
    if (keys.indexOf('ph') < pIdx) props.ph = props.p[0];
    if (keys.indexOf('pv') < pIdx) props.pv = props.p[1];
  } else if (len === 3) {
    if (keys.indexOf('pt') < pIdx) props.pt = p[0];
    if (keys.indexOf('ph') < pIdx) props.ph = p[1];
    if (keys.indexOf('pb') < pIdx) props.pb = p[2];
  } else if (len === 4) {
    if (keys.indexOf('pt') < pIdx) props.pt = p[0];
    if (keys.indexOf('pr') < pIdx) props.pr = p[1];
    if (keys.indexOf('pb') < pIdx) props.pb = p[2];
    if (keys.indexOf('pl') < pIdx) props.pl = p[3];
  }
  delete props.p;
}

export function getBorder(props: TContainerProps) {
  const keys = Object.keys(props);
  if (Array.isArray(props.b)) {
    const bIndex = keys.indexOf('b');
    if (keys.indexOf('bw') < bIndex) props.bw = props.b[0];
    if (keys.indexOf('bc') < bIndex) props.bc = props.b[1] as string;
    if (keys.indexOf('br') < bIndex) props.br = props.b[2];
    delete props.b;
  }
  if (Array.isArray(props.bw)) {
    const bwIdx = keys.indexOf('bw');
    const bw = props.bw;
    if (keys.indexOf('bwt') <= bwIdx) props.bwt = bw[0];
    if (keys.indexOf('bwr') <= bwIdx) props.bwr = bw[1];
    if (keys.indexOf('bwb') <= bwIdx) props.bwb = bw[2];
    if (keys.indexOf('bwl') <= bwIdx) props.bwl = bw[3];
    delete props.bw;
  }
  if (Array.isArray(props.bc)) {
    const bcIdx = keys.indexOf('bc');
    const bc = props.bc;
    if (keys.indexOf('bct') <= bcIdx) props.bct = bc[0];
    if (keys.indexOf('bcr') <= bcIdx) props.bcr = bc[1];
    if (keys.indexOf('bcb') <= bcIdx) props.bcb = bc[2];
    if (keys.indexOf('bcl') <= bcIdx) props.bcl = bc[3];
    delete props.bc;
  }
  if (Array.isArray(props.br)) {
    const brIdx = keys.indexOf('br');
    const br = props.br;
    if (keys.indexOf('brtl') <= brIdx) props.brtl = br[0];
    if (keys.indexOf('brtr') <= brIdx) props.brtr = br[1];
    if (keys.indexOf('brbr') <= brIdx) props.brbr = br[2];
    if (keys.indexOf('brbl') <= brIdx) props.brbl = br[3];
    delete props.br;
  }
}

const aiMap: Record<string, FlexAlignType> = {
  fs: 'flex-start',
  fe: 'flex-end',
  c: 'center',
  s: 'stretch',
  b: 'baseline',
};

const jcMap: Record<
  string,
  | 'flex-start'
  | 'flex-end'
  | 'center'
  | 'space-between'
  | 'space-around'
  | 'space-evenly'
  | undefined
> = {
  c: 'center',
  fs: 'flex-start',
  fe: 'flex-end',
  sb: 'space-between',
  sa: 'space-around',
  se: 'space-evenly',
};
